{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PYNQ Microblaze Libraries in C\n",
    "\n",
    "This document describes the various libraries that ship with PYNQ Microblaze.\n",
    "\n",
    "## `pynqmb`\n",
    "\n",
    "The main library is `pynqmb` which consists of functions for interacting with a variety of I/O devices. `pynqmb` is split into separate `i2c.h`, `gpio.h`, `spi.h`, `timer.h` and `uart.h` header files with each one being self contained. In this notebook we will look just at the I2C and GPIO headers however the full function reference for all of the components can be found on http://pynq.readthedocs.io \n",
    "\n",
    "All of the components follow the same pattern in having `_open` function calls that take one or more pins depending on the protocol. These function use an I/O switch in the subsystem to connect the protocol controller to the output pins. For devices not connected to output pins there are `_open_device` functions which take either the base address of the controller or it's index as defined in the board support package.\n",
    "\n",
    "For this example we are going to use a Grove ADC connected via Pmod-Grove adapter and using the I2C protocol. One ancilliary header file that is useful when using the Pmod-Grove adapter is `pmod_grove.h` which includes the pin definitions for the adapter board. In this case we are using the G4 port on the adapter which is connected to pins 6 and 2 of the Pmod connector."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "\n",
       "require(['notebook/js/codecell'], function(codecell) {\n",
       "  codecell.CodeCell.options_default.highlight_modes[\n",
       "      'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n",
       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
       "      Jupyter.notebook.get_cells().map(function(cell){\n",
       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
       "  });\n",
       "});\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from pynq.overlays.base import BaseOverlay\n",
    "base = BaseOverlay('base.bit')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze base.PMODA\n",
    "#include <i2c.h>\n",
    "#include <pmod_grove.h>\n",
    "\n",
    "int read_adc() {\n",
    "    i2c device = i2c_open(PMOD_G4_B, PMOD_G4_A);\n",
    "    unsigned char buf[2];\n",
    "    buf[0] = 0;\n",
    "    i2c_write(device, 0x50, buf, 1);\n",
    "    i2c_read(device, 0x50, buf, 2);\n",
    "    return ((buf[0] & 0x0F) << 8) | buf[1];\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "833"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "read_adc()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use the `gpio` and `timer` components in concert to flash an LED connected to G1. The `timer` header provides PWM and program delay functionality, although only one can be used simultaneously."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze base.PMODA\n",
    "#include <timer.h>\n",
    "#include <gpio.h>\n",
    "#include <pmod_grove.h>\n",
    "\n",
    "void flash_led() {\n",
    "    gpio led = gpio_open(PMOD_G1_A);\n",
    "    gpio_set_direction(led, GPIO_OUT);\n",
    "    int state = 0;\n",
    "    while (1) {\n",
    "        gpio_write(led, state);\n",
    "        state = !state;\n",
    "        delay_ms(500);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "flash_led()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `pyprintf`\n",
    "\n",
    "The `pyprint` library exposes a single `pyprintf` function which acts similarly to a regular `printf` function but forwards arguments to Python for formatting and display result in far lower code overhead than a regular printf as well as not requiring access to standard in and out."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze base.PMODA\n",
    "#include <pyprintf.h>\n",
    "\n",
    "int test_print(float value) {\n",
    "    pyprintf(\"Printing %f from the microblaze!\\n\", value);\n",
    "    return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Printing 1.500000 from the microblaze!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_print(1.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At present, `pyprintf` can support the common subset of datatype between Python and C - in particular `%{douxXfFgGeEsc}`. Long data types and additional format modifiers are not supported yet."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
